#include "list.h"
#include "TimeWheel.h"
#include <stdio.h>

int test_count = 0, test_pass = 0, main_ret = 0;

#define EXPECT_EQ_BASE(equality, expect, actual, format) \
    do {\
        test_count++;\
        if (equality)\
            test_pass++;\
        else {\
            fprintf(stderr, "%s:%d: expect: " format " actual: " format "\n", __FILE__, __LINE__, expect, actual);\
            main_ret = 1;\
        }\
    } while(0)

#define EXPECT_EQ_INT(expect, actual) EXPECT_EQ_BASE((expect) == (actual), expect, actual, "%d")
#define EXPECT_EQ_POINTER(expect, actual) EXPECT_EQ_BASE(((void*)expect) == (void*)(actual), (void*)expect, (void*)actual, "%p")

#define TEST_LEVEL 4
#define TEST_FREQUENCE 1000
uint8_t arr[TEST_LEVEL] = {8, 4, 4, 4};
uint32_t actSum = 0;
twb_t *TWB;

uint32_t printLog(void* param)
{
    if(TWB->tick != (uint64_t)param)
        printf("[log]tick:%p,%p\n", (int*)TWB->tick, (int*)param);
    // printf("time[%I64d]tick[%I64d]\n", tw_get_time(TWB), tw_get_tick(TWB));
    actSum++;
    return 0;
}

void create_test(void)
{
    int i;
    actSum = 0;
    TWB = tw_create_twb(TEST_LEVEL, arr, TEST_FREQUENCE);
    if(TWB != NULL) actSum = TWB->level;
    EXPECT_EQ_INT(TEST_LEVEL, actSum);

    for (i = 0; i < TEST_LEVEL; ++i)
    {
        if (TWB->twu[i]->size != (1<<arr[i])) break;
    }
    EXPECT_EQ_INT(TEST_LEVEL, i);
}

void addTimer_test(void)
{
    int i = TEST_LEVEL;
    uint64_t mul = 0;
    uint64_t ticktime;
    for (i = 0; i < TEST_LEVEL; ++i)
    {
        mul += arr[i];
        ticktime = (1ULL<<mul) - 1;
        tw_task_create(TWB, (twTick_t)ticktime, printLog, (uint32_t*)ticktime, i);
        tw_task_create(TWB, (twTick_t)ticktime, printLog, (uint32_t*)ticktime, i);
    }
}

void findTimer_test(void)
{
    actSum = 0;
    twt_t *ptwt = NULL;
    int i;
    for (i = 0; i < TEST_LEVEL; ++i)
    {
        ptwt = tw_task_find_id(TWB, i);
        if(ptwt != NULL && ptwt->id == i)
            actSum++;
    }
    EXPECT_EQ_INT(TEST_LEVEL, actSum);
}

void runTimer_test(void)
{
    actSum = 0;
    uint64_t ticktime = 1ULL<<TWB->bitSize;
    while (ticktime--)
    {
        tw_run(TWB);
    }
    EXPECT_EQ_INT(TEST_LEVEL * 2, actSum);
}

uint32_t paramSet(void *data)
{
    tw_task_set_param_internal(TWB, (int*)1);
    return 1;
}

void setParam_test(void)
{
    twt_t *ptwt;
    actSum = 0;
    tw_task_create(TWB, 1, paramSet, NULL, TEST_LEVEL);
    ptwt = tw_task_find_id(TWB, TEST_LEVEL);
    tw_run(TWB);
    EXPECT_EQ_POINTER((int*)1, (int*)ptwt->param);

    tw_task_set_param_id(TWB, TEST_LEVEL, (int*)2);
    EXPECT_EQ_POINTER((int*)2, (int*)ptwt->param);

    tw_task_set_param(ptwt, (int*)3);
    EXPECT_EQ_POINTER((int*)3, (int*)ptwt->param);
}

void deleteTimer_test(void)
{
    twt_t *ptwt = NULL;
    int i = 0;
    tw_task_destroy_id(TWB, TEST_LEVEL);
    ptwt = tw_task_find_id(TWB, TEST_LEVEL);
    EXPECT_EQ_POINTER(NULL, ptwt);

    actSum = 0;
    for (i = 0; i < 10; i++)
    {
        tw_task_create(TWB, i + 1, paramSet, NULL, TEST_LEVEL + i);
    }
    tw_task_destroy_function(TWB, paramSet);
    for (i = 0; i < 10; i++)
    {
        ptwt = tw_task_find_id(TWB, TEST_LEVEL + i);
        if(ptwt == NULL)
            actSum++;
    }
    EXPECT_EQ_INT(10, actSum);
    
}


void destory_test(void)
{
    tw_destroy_twb(&TWB);
    // listDestroy(&(TWB->twu[0]->list[0]));
    EXPECT_EQ_POINTER(NULL, TWB);
}

int main(void)
{
    int count = 1;
    while (count--)
    {
        create_test();
        addTimer_test();
        findTimer_test();
        runTimer_test();
        setParam_test();
        deleteTimer_test();
        destory_test();
        printf("result: %d/%d (%3.2f%%) passed\n", test_pass, test_count, test_pass * 100.0 / test_count);
    }

    return main_ret;
}
